<!DOCTYPE html>
<!-- saved from url=(0118)http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9 -->
<html lang="en" dir="ltr" class="client-js"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin</title>
<meta charset="UTF-8">
<meta name="generator" content="MediaWiki 1.19.2">
<link rel="shortcut icon" href="http://roguebasin.roguelikedevelopment.org/favicon.ico">
<link rel="search" type="application/opensearchdescription+xml" href="http://roguebasin.roguelikedevelopment.org/opensearch_desc.php" title="RogueBasin (en)">
<link rel="EditURI" type="application/rsd+xml" href="http://roguebasin.roguelikedevelopment.org/api.php?action=rsd">
<link rel="alternate" type="application/atom+xml" title="RogueBasin Atom feed" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges&feed=atom">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=mediawiki.legacy.commonPrint%2Cshared%7Cskins.monobook&only=styles&skin=monobook&*">
<!--[if IE 6]><link rel="stylesheet" href="/skins/monobook/IE60Fixes.css?303" media="screen" /><![endif]-->
<!--[if IE 7]><link rel="stylesheet" href="/skins/monobook/IE70Fixes.css?303" media="screen" /><![endif]--><style type="text/css" media="all">.js-messagebox{margin:1em 5%;padding:0.5em 2.5%;border:1px solid #ccc;background-color:#fcfcfc;font-size:0.8em}.js-messagebox .js-messagebox-group{margin:1px;padding:0.5em 2.5%;border-bottom:1px solid #ddd}.js-messagebox .js-messagebox-group:last-child{border-bottom:thin none transparent}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:8b08bdc91c52a9ffba396dccfb5b473c */


.mw-collapsible-toggle{float:right} li .mw-collapsible-toggle{float:none} .mw-collapsible-toggle-li{list-style:none}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:4250852ed2349a0d4d0fc6509a3e7d4c */
</style><meta name="ResourceLoaderDynamicStyles" content="">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=site&only=styles&skin=monobook&*">
<style>a:lang(ar),a:lang(ckb),a:lang(fa),a:lang(kk-arab),a:lang(mzn),a:lang(ps),a:lang(ur){text-decoration:none}a.new,#quickbar a.new{color:#ba0000}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:c88e2bcd56513749bec09a7e29cb3ffa */
</style>

<script src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/load.php"></script><style type="text/css"></style><script src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/load(1).php"></script>
<script>if(window.mw){
mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_9","wgTitle":"Complete Roguelike Tutorial, using python+libtcod, part 9","wgCurRevisionId":35444,"wgArticleId":3917,"wgIsArticle":true,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Developing"],"wgBreakFrames":false,"wgPageContentLanguage":"en","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgRelevantPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_9","wgRestrictionEdit":[],"wgRestrictionMove":[]});
}</script><script>if(window.mw){
mw.loader.implement("user.options",function($){mw.user.options.set({"ccmeonemails":0,"cols":80,"date":"default","diffonly":0,"disablemail":0,"disablesuggest":0,"editfont":"default","editondblclick":0,"editsection":1,"editsectiononrightclick":0,"enotifminoredits":0,"enotifrevealaddr":0,"enotifusertalkpages":1,"enotifwatchlistpages":0,"extendwatchlist":0,"externaldiff":0,"externaleditor":0,"fancysig":0,"forceeditsummary":0,"gender":"unknown","hideminor":0,"hidepatrolled":0,"highlightbroken":1,"imagesize":2,"justify":0,"math":1,"minordefault":0,"newpageshidepatrolled":0,"nocache":0,"noconvertlink":0,"norollbackdiff":0,"numberheadings":0,"previewonfirst":0,"previewontop":1,"quickbar":5,"rcdays":7,"rclimit":50,"rememberpassword":0,"rows":25,"searchlimit":20,"showhiddencats":0,"showjumplinks":1,"shownumberswatching":1,"showtoc":1,"showtoolbar":1,"skin":"monobook","stubthreshold":0,"thumbsize":2,"underline":2,"uselivepreview":0,"usenewrc":0,"watchcreations":0,"watchdefault":0,"watchdeletion":
0,"watchlistdays":3,"watchlisthideanons":0,"watchlisthidebots":0,"watchlisthideliu":0,"watchlisthideminor":0,"watchlisthideown":0,"watchlisthidepatrolled":0,"watchmoves":0,"wllimit":250,"variant":"en","language":"en","searchNs0":true,"searchNs1":false,"searchNs2":false,"searchNs3":false,"searchNs4":false,"searchNs5":false,"searchNs6":false,"searchNs7":false,"searchNs8":false,"searchNs9":false,"searchNs10":false,"searchNs11":false,"searchNs12":false,"searchNs13":false,"searchNs14":false,"searchNs15":false});;},{},{});mw.loader.implement("user.tokens",function($){mw.user.tokens.set({"editToken":"+\\","watchToken":false});;},{},{});

/* cache key: 133099-basin:resourceloader:filter:minify-js:7:74a832f2292f1f4d40d425d223444e78 */
}</script>
<script>if(window.mw){
mw.loader.load(["mediawiki.page.startup","mediawiki.legacy.wikibits","mediawiki.legacy.ajax"]);
}</script><script type="text/javascript" src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/load(2).php"></script>
<style type="text/css">/*<![CDATA[*/
.source-python {line-height: normal;}
.source-python li, .source-python pre {
	line-height: normal; border: 0px none white;
}
/**
 * GeSHi Dynamically Generated Stylesheet
 * --------------------------------------
 * Dynamically generated stylesheet for python
 * CSS class: source-python, CSS id: 
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 * --------------------------------------
 */
.python.source-python .de1, .python.source-python .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.python.source-python  {font-family:monospace;}
.python.source-python .imp {font-weight: bold; color: red;}
.python.source-python li, .python.source-python .li1 {font-weight: normal; vertical-align:top;}
.python.source-python .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.python.source-python .li2 {font-weight: bold; vertical-align:top;}
.python.source-python .kw1 {color: #ff7700;font-weight:bold;}
.python.source-python .kw2 {color: #008000;}
.python.source-python .kw3 {color: #dc143c;}
.python.source-python .kw4 {color: #0000cd;}
.python.source-python .co1 {color: #808080; font-style: italic;}
.python.source-python .coMULTI {color: #808080; font-style: italic;}
.python.source-python .es0 {color: #000099; font-weight: bold;}
.python.source-python .br0 {color: black;}
.python.source-python .sy0 {color: #66cc66;}
.python.source-python .st0 {color: #483d8b;}
.python.source-python .nu0 {color: #ff4500;}
.python.source-python .me1 {color: black;}
.python.source-python .ln-xtra, .python.source-python li.ln-xtra, .python.source-python div.ln-xtra {background-color: #ffc;}
.python.source-python span.xtra { display:block; }

/*]]>*/
</style>
<style type="text/css">/*<![CDATA[*/
@import "/index.php?title=MediaWiki:Geshi.css&usemsgcache=yes&action=raw&ctype=text/css&smaxage=18000";
/*]]>*/
</style></head>
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-Complete_Roguelike_Tutorial_using_python_libtcod_part_9 skin-monobook action-view">
<div id="globalWrapper">
<div id="column-content"><div id="content"><div id="mw-js-message" class="js-messagebox" style="display: none;"></div>
	<a id="top"></a>
	<div id="siteNotice"><div id="localNotice" lang="en" dir="ltr"></div></div>
	<h1 id="firstHeading" class="firstHeading"><span dir="auto">Complete Roguelike Tutorial, using python+libtcod, part 9</span></h1>
	<div id="bodyContent" class="mw-body">
		<div id="siteSub">From RogueBasin</div>
		<div id="contentSub"></div>
		<div id="jump-to-nav" class="mw-jump">Jump to: <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#column-one">navigation</a>, <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#searchInput">search</a></div>
		<!-- start content -->
<div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr"><center><table border="0" cellpadding="10" cellspacing="0" style="background:#F0E68C"><tbody><tr><td><center>
<p>This is part of a series of tutorials; the main page can be found <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod" title="Complete Roguelike Tutorial, using python+libtcod">here</a>.
</p><p>The tutorial uses libctod version 1.5.1. If you prefer to use 1.5.0, you can find the old version <a rel="nofollow" class="external text" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&oldid=29877">here</a>
</p>
</center></td></tr></tbody></table></center>
<p><br>
</p>
<table id="toc" class="toc"><tbody><tr><td><div id="toctitle"><h2>Contents</h2><span class="toctoggle">&nbsp;[<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#" class="internal" id="togglelink">hide</a>]&nbsp;</span></div>
<ul>
<li class="toclevel-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Spells_and_ranged_combat"><span class="tocnumber">1</span> <span class="toctext"><b>Spells and ranged combat</b></span></a>
<ul>
<li class="toclevel-2 tocsection-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Magic_scrolls:_the_Lightning_Bolt"><span class="tocnumber">1.1</span> <span class="toctext">Magic scrolls: the Lightning Bolt</span></a></li>
<li class="toclevel-2 tocsection-2"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Spells_that_manipulate_monsters:_Confusion"><span class="tocnumber">1.2</span> <span class="toctext">Spells that manipulate monsters: Confusion</span></a></li>
<li class="toclevel-2 tocsection-3"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Targeting:_the_Fireball"><span class="tocnumber">1.3</span> <span class="toctext">Targeting: the Fireball</span></a></li>
<li class="toclevel-2 tocsection-4"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Targeting_single_monsters"><span class="tocnumber">1.4</span> <span class="toctext">Targeting single monsters</span></a></li>
<li class="toclevel-2 tocsection-5"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9#Dropping_items"><span class="tocnumber">1.5</span> <span class="toctext">Dropping items</span></a></li>
</ul>
</li>
</ul>
</td></tr></tbody></table>
<p><br>
</p>
<center><h1> <span class="mw-headline" id="Spells_and_ranged_combat"><b>Spells and ranged combat</b></span></h1></center>
<p><br>
</p>
<h2> <span class="mw-headline" id="Magic_scrolls:_the_Lightning_Bolt"> Magic scrolls: the Lightning Bolt </span></h2>
<p>The inventory we implemented has lots of untapped potential; I encourage you to explore it fully and create as many different items as possible! (Though the special category of items that can be equipped, like swords and armor, will be done in a later section.) To get the ball rolling, we'll start with some magic scrolls the player can use to cast spells. We'll sample a few different spell types; I'm sure you can then create tons of variants from these little examples.
</p><p>The first spell is a lightning bolt that damages the nearest enemy. It's simple to code because it doesn't involve any targeting. On the other hand, it creates some interesting tactical challenges: if the nearest enemy is not the one you want to hit (for example, it's too weak to waste the spell on it), you have to maneuver into a good position. Just modify the <i>place_objects</i> function to choose at random between a healing potion and a lightning bolt scroll, the same way it's done with monsters:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            dice = libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">100</span><span class="br0">)</span>
            <span class="kw1">if</span> dice <span class="sy0">&lt;</span> <span class="nu0">70</span>:
                <span class="co1">#create a healing potion (70% chance)</span>
                item_component = Item<span class="br0">(</span>use_function=cast_heal<span class="br0">)</span>
&nbsp;
                item = Object<span class="br0">(</span>x, y, <span class="st0">'!'</span>, <span class="st0">'healing potion'</span>, libtcod.<span class="me1">violet</span>, item=item_component<span class="br0">)</span>
            <span class="kw1">else</span>:
                <span class="co1">#create a lightning bolt scroll (30% chance)</span>
                item_component = Item<span class="br0">(</span>use_function=cast_lightning<span class="br0">)</span>
&nbsp;
                item = Object<span class="br0">(</span>x, y, <span class="st0">'#'</span>, <span class="st0">'scroll of lightning bolt'</span>, libtcod.<span class="me1">light_yellow</span>, item=item_component<span class="br0">)</span></pre></div></div></div>
<p><br>
When used, the new item calls the <i>cast_lightning</i> function. It's quite simple, and many of the spells will be equally short if you define some functions for common tasks. One of those common tasks is finding the nearest monster up to a maximum range, which we'll get to in a second; but first, the lightning bolt spell:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> cast_lightning<span class="br0">(</span><span class="br0">)</span>:
    <span class="co1">#find closest enemy (inside a maximum range) and damage it</span>
    monster = closest_monster<span class="br0">(</span>LIGHTNING_RANGE<span class="br0">)</span>
    <span class="kw1">if</span> monster <span class="kw1">is</span> <span class="kw2">None</span>:  <span class="co1">#no enemy found within maximum range</span>
        message<span class="br0">(</span><span class="st0">'No enemy is close enough to strike.'</span>, libtcod.<span class="me1">red</span><span class="br0">)</span>
        <span class="kw1">return</span> <span class="st0">'cancelled'</span>
&nbsp;
    <span class="co1">#zap it!</span>
    message<span class="br0">(</span><span class="st0">'A lighting bolt strikes the '</span> + monster.<span class="me1">name</span> + <span class="st0">' with a loud thunder! The damage is '</span>
        + <span class="kw2">str</span><span class="br0">(</span>LIGHTNING_DAMAGE<span class="br0">)</span> + <span class="st0">' hit points.'</span>, libtcod.<span class="me1">light_blue</span><span class="br0">)</span>
    monster.<span class="me1">fighter</span>.<span class="me1">take_damage</span><span class="br0">(</span>LIGHTNING_DAMAGE<span class="br0">)</span></pre></div></div></div>
<p><br>
It's a plain spell but an imaginative message can always give it some flavor! It returns a special string if cancelled to prevent the item from being destroyed in that case, like the healing potion. There are also a couple of new constants that have to be defined: <i>LIGHTNING_DAMAGE = 20</i> and <i>LIGHTNING_RANGE = 5</i>.
</p><p>Now the <i>closest_monster</i> function. We just need to loop through all the monsters, and keep track of the closest one so far (and its distance). By initializing that distance at a bit more than the maximum range, any monster farther away is rejected. We also check that it's in FOV, so the player can't cast a spell through walls.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> closest_monster<span class="br0">(</span>max_range<span class="br0">)</span>:
    <span class="co1">#find closest enemy, up to a maximum range, and in the player's FOV</span>
    closest_enemy = <span class="kw2">None</span>
    closest_dist = max_range + <span class="nu0">1</span>  <span class="co1">#start with (slightly more than) maximum range</span>
&nbsp;
    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw1">if</span> <span class="kw2">object</span>.<span class="me1">fighter</span> <span class="kw1">and</span> <span class="kw1">not</span> <span class="kw2">object</span> == player <span class="kw1">and</span> libtcod.<span class="me1">map_is_in_fov</span><span class="br0">(</span>fov_map, <span class="kw2">object</span>.<span class="me1">x</span>, <span class="kw2">object</span>.<span class="me1">y</span><span class="br0">)</span>:
            <span class="co1">#calculate distance between this object and the player</span>
            dist = player.<span class="me1">distance_to</span><span class="br0">(</span><span class="kw2">object</span><span class="br0">)</span>
            <span class="kw1">if</span> dist <span class="sy0">&lt;</span> closest_dist:  <span class="co1">#it's closer, so remember it</span>
                closest_enemy = <span class="kw2">object</span>
                closest_dist = dist
    <span class="kw1">return</span> closest_enemy</pre></div></div></div>
<p><br>
This makes use of the <i>distance_to</i> method we wrote earlier for the AI. Alright, the lightning bolt is done! If you have one you can take down a Troll with a single hit, sparing you from a lot of damage.
</p><p><br>
</p>
<h2> <span class="mw-headline" id="Spells_that_manipulate_monsters:_Confusion"> Spells that manipulate monsters: Confusion </span></h2>
<p>There are many direct damage variants of the Lightning Bolt spell. So we'll move on to a different sort of spell: one that affects the monsters' actions. This can be done by replacing their AI with a different one, that makes it do something different -- run away in fear, stay knocked out for a few turns, even fight on the player's side for a while!
</p><p>My choice was a Confusion spell, that makes the monster move around randomly, and not attack the player. The AI component that does this is very similar to a regular one, since it defines a <i>take_turn</i> method. It could look like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">class</span> ConfusedMonster:
    <span class="co1">#AI for a confused monster.</span>
    <span class="kw1">def</span> take_turn<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="co1">#move in a random direction</span>
        <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">move</span><span class="br0">(</span>libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">)</span>, libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span></pre></div></div></div>
<p><br>
Which simply moves in a random direction (random X and Y displacements between -1 and 1).
</p><p>It shouldn't go on forever of course, and after the spell runs out the previous AI must restored. So it must accept the previous AI component as an argument to store it. It must also keep track of the number of turns left until the effect ends:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">class</span> ConfusedMonster:
    <span class="co1">#AI for a temporarily confused monster (reverts to previous AI after a while).</span>
    <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span>, old_ai, num_turns=CONFUSE_NUM_TURNS<span class="br0">)</span>:
        <span class="kw2">self</span>.<span class="me1">old_ai</span> = old_ai
        <span class="kw2">self</span>.<span class="me1">num_turns</span> = num_turns
&nbsp;
    <span class="kw1">def</span> take_turn<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="kw1">if</span> <span class="kw2">self</span>.<span class="me1">num_turns</span> <span class="sy0">&gt;</span> <span class="nu0">0</span>:  <span class="co1">#still confused...</span>
            <span class="co1">#move in a random direction, and decrease the number of turns confused</span>
            <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">move</span><span class="br0">(</span>libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">)</span>, libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span>
            <span class="kw2">self</span>.<span class="me1">num_turns</span> -= <span class="nu0">1</span>
&nbsp;
        <span class="kw1">else</span>:  <span class="co1">#restore the previous AI (this one will be deleted because it's not referenced anymore)</span>
            <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">ai</span> = <span class="kw2">self</span>.<span class="me1">old_ai</span>
            message<span class="br0">(</span><span class="st0">'The '</span> + <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">name</span> + <span class="st0">' is no longer confused!'</span>, libtcod.<span class="me1">red</span><span class="br0">)</span></pre></div></div></div>
<p><br>
I defined the new constant <i>CONFUSE_NUM_TURNS = 10</i>. Now, the actual scroll that uses this AI! For it to appear in the dungeon it must be added to <i>place_objects</i>. Notice that the chance of getting a lightning bolt scroll must change:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            <span class="kw1">elif</span> dice <span class="sy0">&lt;</span> <span class="nu0">70</span>+<span class="nu0">15</span>:
                <span class="co1">#create a lightning bolt scroll (15% chance)</span>
                item_component = Item<span class="br0">(</span>use_function=cast_lightning<span class="br0">)</span>
&nbsp;
                item = Object<span class="br0">(</span>x, y, <span class="st0">'#'</span>, <span class="st0">'scroll of lightning bolt'</span>, libtcod.<span class="me1">light_yellow</span>, item=item_component<span class="br0">)</span>
            <span class="kw1">else</span>:
                <span class="co1">#create a confuse scroll (15% chance)</span>
                item_component = Item<span class="br0">(</span>use_function=cast_confuse<span class="br0">)</span>
&nbsp;
                item = Object<span class="br0">(</span>x, y, <span class="st0">'#'</span>, <span class="st0">'scroll of confusion'</span>, libtcod.<span class="me1">light_yellow</span>, item=item_component<span class="br0">)</span></pre></div></div></div>
<p><br>
I'm making all scrolls look the same, but in your game that's up to you. The <i>cast_confuse</i> function can now be defined. It hits the closest monster for now, like the lightning bolt; later we'll allow targeting.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> cast_confuse<span class="br0">(</span><span class="br0">)</span>:
    <span class="co1">#find closest enemy in-range and confuse it</span>
    monster = closest_monster<span class="br0">(</span>CONFUSE_RANGE<span class="br0">)</span>
    <span class="kw1">if</span> monster <span class="kw1">is</span> <span class="kw2">None</span>:  <span class="co1">#no enemy found within maximum range</span>
        message<span class="br0">(</span><span class="st0">'No enemy is close enough to confuse.'</span>, libtcod.<span class="me1">red</span><span class="br0">)</span>
        <span class="kw1">return</span> <span class="st0">'cancelled'</span></pre></div></div></div>
<p><br>
This uses the constant <i>CONFUSE_RANGE = 8</i>. Components are "plug &amp; play" so they only take a couple of lines of code to replace! What this does is assign a new "confused AI" component to the monster, giving it the previous AI component as an argument. Then its "owner" property is set to the monster, otherwise the new component wouldn't know what monster it belongs to.
</p><p>Setting the "owner" has to be done every time you replace a component in the middle of the game. To top it off, print a nice message describing what happened.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="co1">#replace the monster's AI with a "confused" one; after some turns it will restore the old AI</span>
    old_ai = monster.<span class="me1">ai</span>
    monster.<span class="me1">ai</span> = ConfusedMonster<span class="br0">(</span>old_ai<span class="br0">)</span>
    monster.<span class="me1">ai</span>.<span class="me1">owner</span> = monster  <span class="co1">#tell the new component who owns it</span>
    message<span class="br0">(</span><span class="st0">'The eyes of the '</span> + monster.<span class="me1">name</span> + <span class="st0">' look vacant, as he starts to stumble around!'</span>, libtcod.<span class="me1">light_green</span><span class="br0">)</span></pre></div></div></div>
<p><br>
This seems like a neat way to interrupt a monster's actions in reaction to something. It is, but not for every situation! You could create a full finite state machine by just swapping AI components, but such a system would be very hard to debug. Instead, for most types of AI that have different states, you can simply have a "state" property in the AI component, like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">class</span> DragonAI:
    <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="kw2">self</span>.<span class="me1">state</span> = <span class="st0">'chasing'</span>
&nbsp;
    <span class="kw1">def</span> take_turn<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="kw1">if</span> <span class="kw2">self</span>.<span class="me1">state</span> == <span class="st0">'chasing'</span>: ...
        <span class="kw1">elif</span> <span class="kw2">self</span>.<span class="me1">state</span> == <span class="st0">'charging-fire-breath'</span>: ...</pre></div></div></div>
<p><br>
Swapping AI components is most useful for unexpected interruptions, such as when a spell is cast. The BasicMonster or DragonAI shouldn't know what to do when confused; that depends on the spell. They do know, however, what to do in normal situations (attacking, etc), and those behaviors usually don't belong in other AI components; if a single AI is composed of too many small interacting parts, they can be harder to maintain. This is just a piece of advice though, and in programming common sense always wins over any hard rules.
</p><p><br>
</p>
<h2> <span class="mw-headline" id="Targeting:_the_Fireball"> Targeting: the Fireball </span></h2>
<p>Given that we know how to make direct damage spells like Lightning Bolt, others like Blizzard or Fireball are just a matter of finding all monsters in an area and damaging them; you should have no trouble creating them. But it would be much more interesting if the player could choose the target properly, and that's a feature that will benefit many spells. In addition, you can use the same system for ranged weapons like crossbows or slings. So let's do that!
</p><p>We're gonna build a mouse interface. It's also possible to make a classic keyboard interface, but it would be less intuitive and a bit harder to code; if you prefer that, consider it a small challenge!
</p><p>We already have some code for getting the coordinates of the mouse, and checking for left-clicks is trivial -- when it happens <i>mouse.lbutton_pressed</i> is True. So we just need to loop until the player clicks somewhere. By redrawing the screen with every loop, the names of objects under the mouse are automatically shown, and we erase the inventory from which the player chose the scroll (otherwise it would still be visible).
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> target_tile<span class="br0">(</span>max_range=<span class="kw2">None</span><span class="br0">)</span>:
    <span class="co1">#return the position of a tile left-clicked in player's FOV (optionally in a range), or (None,None) if right-clicked.</span>
    <span class="kw1">global</span> key, mouse
    <span class="kw1">while</span> <span class="kw2">True</span>:
        <span class="co1">#render the screen. this erases the inventory and shows the names of objects under the mouse.</span>
        libtcod.<span class="me1">console_flush</span><span class="br0">(</span><span class="br0">)</span>
        libtcod.<span class="me1">sys_check_for_event</span><span class="br0">(</span>libtcod.<span class="me1">EVENT_KEY_PRESS</span>|libtcod.<span class="me1">EVENT_MOUSE</span>,key,mouse<span class="br0">)</span>
        render_all<span class="br0">(</span><span class="br0">)</span>
&nbsp;
        <span class="br0">(</span>x, y<span class="br0">)</span> = <span class="br0">(</span>mouse.<span class="me1">cx</span>, mouse.<span class="me1">cy</span><span class="br0">)</span>
&nbsp;
        <span class="kw1">if</span> mouse.<span class="me1">lbutton_pressed</span>:
            <span class="kw1">return</span> <span class="br0">(</span>x, y<span class="br0">)</span></pre></div></div></div>
<p><br>
We have to "flush" the console to present the changes to the player, and <i>console_check_for_keypress</i> absorbs any keys the player presses during the loop, doing nothing with them. Otherwise, if you pressed a key before clicking, it would be stored by libtcod and processed <i>after</i> you clicked, which is unexpected. This does the job, but there are a few things missing! First, there's no way to cancel. We'll define the right-click and the Escape key as ways to cancel, and return a special code:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="kw1">if</span> mouse.<span class="me1">rbutton_pressed</span> <span class="kw1">or</span> key.<span class="me1">vk</span> == libtcod.<span class="me1">KEY_ESCAPE</span>:
            <span class="kw1">return</span> <span class="br0">(</span><span class="kw2">None</span>, <span class="kw2">None</span><span class="br0">)</span>  <span class="co1">#cancel if the player right-clicked or pressed Escape</span></pre></div></div></div>
<p><br>
If it returned <i>None</i> instead, calling <i>(x,y) = target_tile()</i> would give an error, since we expect 2 output arguments (in fact, it's a tuple that is <i>unpacked</i> to variables <i>x</i> and <i>y</i>). So <i>target_tile</i> must return <i>(None, None)</i> when canceling.
</p><p>Ok, we also want to avoid targeting out-of-FOV, to prevent firing through walls. An optional maximum range would also be nice. Replace the <i>if mouse.lbutton_pressed:</i> line with:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="co1">#accept the target if the player clicked in FOV, and in case a range is specified, if it's in that range</span>
        <span class="kw1">if</span> <span class="br0">(</span>mouse.<span class="me1">lbutton_pressed</span> <span class="kw1">and</span> libtcod.<span class="me1">map_is_in_fov</span><span class="br0">(</span>fov_map, x, y<span class="br0">)</span> <span class="kw1">and</span>
            <span class="br0">(</span>max_range <span class="kw1">is</span> <span class="kw2">None</span> <span class="kw1">or</span> player.<span class="me1">distance</span><span class="br0">(</span>x, y<span class="br0">)</span> <span class="sy0">&lt;</span>= max_range<span class="br0">)</span><span class="br0">)</span>:</pre></div></div></div>
<p><br>
The Object class already has a method that returns the distance between 2 objects, but we'll add another one, that returns the distance between that object and a tile. It's used in the above line of code and will be handy in the future.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">def</span> distance<span class="br0">(</span><span class="kw2">self</span>, x, y<span class="br0">)</span>:
        <span class="co1">#return the distance to some coordinates</span>
        <span class="kw1">return</span> <span class="kw3">math</span>.<span class="me1">sqrt</span><span class="br0">(</span><span class="br0">(</span>x - <span class="kw2">self</span>.<span class="me1">x</span><span class="br0">)</span> <span class="sy0">**</span> <span class="nu0">2</span> + <span class="br0">(</span>y - <span class="kw2">self</span>.<span class="me1">y</span><span class="br0">)</span> <span class="sy0">**</span> <span class="nu0">2</span><span class="br0">)</span></pre></div></div></div>
<p><br>
That's all for targeting a tile! We can now create a simple fireball spell:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> cast_fireball<span class="br0">(</span><span class="br0">)</span>:
    <span class="co1">#ask the player for a target tile to throw a fireball at</span>
    message<span class="br0">(</span><span class="st0">'Left-click a target tile for the fireball, or right-click to cancel.'</span>, libtcod.<span class="me1">light_cyan</span><span class="br0">)</span>
    <span class="br0">(</span>x, y<span class="br0">)</span> = target_tile<span class="br0">(</span><span class="br0">)</span>
    <span class="kw1">if</span> x <span class="kw1">is</span> <span class="kw2">None</span>: <span class="kw1">return</span> <span class="st0">'cancelled'</span>
    message<span class="br0">(</span><span class="st0">'The fireball explodes, burning everything within '</span> + <span class="kw2">str</span><span class="br0">(</span>FIREBALL_RADIUS<span class="br0">)</span> + <span class="st0">' tiles!'</span>, libtcod.<span class="me1">orange</span><span class="br0">)</span>
&nbsp;
    <span class="kw1">for</span> obj <span class="kw1">in</span> objects:  <span class="co1">#damage every fighter in range, including the player</span>
        <span class="kw1">if</span> obj.<span class="me1">distance</span><span class="br0">(</span>x, y<span class="br0">)</span> <span class="sy0">&lt;</span>= FIREBALL_RADIUS <span class="kw1">and</span> obj.<span class="me1">fighter</span>:
            message<span class="br0">(</span><span class="st0">'The '</span> + obj.<span class="me1">name</span> + <span class="st0">' gets burned for '</span> + <span class="kw2">str</span><span class="br0">(</span>FIREBALL_DAMAGE<span class="br0">)</span> + <span class="st0">' hit points.'</span>, libtcod.<span class="me1">orange</span><span class="br0">)</span>
            obj.<span class="me1">fighter</span>.<span class="me1">take_damage</span><span class="br0">(</span>FIREBALL_DAMAGE<span class="br0">)</span></pre></div></div></div>
<p><br>
With some new constants <i>FIREBALL_RADIUS = 3</i> and <i>FIREBALL_DAMAGE = 12</i>. This also uses the new <i>distance</i> method. A scroll that casts the Fireball spell must be added to <i>place_objects</i>, before the Confuse scroll:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            <span class="kw1">elif</span> dice <span class="sy0">&lt;</span> <span class="nu0">70</span>+<span class="nu0">10</span>+<span class="nu0">10</span>:
                <span class="co1">#create a fireball scroll (10% chance)</span>
                item_component = Item<span class="br0">(</span>use_function=cast_fireball<span class="br0">)</span>
&nbsp;
                item = Object<span class="br0">(</span>x, y, <span class="st0">'#'</span>, <span class="st0">'scroll of fireball'</span>, libtcod.<span class="me1">light_yellow</span>, item=item_component<span class="br0">)</span></pre></div></div></div>
<p><br>
And change all the "15" to "10"; since there are 3 scrolls now, each one has a 10% chance of appearing. You can now pick up Fireball scrolls; they're quite handy to roast large groups of Orcs! Try not to get burnt though, it also damages the player. I think it adds some strategic value, balancing the spell. (If you want the player to be immune, add "<i>and obj&nbsp;!= player</i>" to the <i>if</i> condition in <i>cast_fireball</i>.)
</p><p><br>
</p>
<h2> <span class="mw-headline" id="Targeting_single_monsters"> Targeting single monsters </span></h2>
<p>Let's not stop there! Area spells like the Fireball are fine, but many spells affect single monsters. Can we make a handy function to target a single monster? Sure! It will simply wrap <i>target_tile</i> and stop only when a monster is selected.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> target_monster<span class="br0">(</span>max_range=<span class="kw2">None</span><span class="br0">)</span>:
    <span class="co1">#returns a clicked monster inside FOV up to a range, or None if right-clicked</span>
    <span class="kw1">while</span> <span class="kw2">True</span>:
        <span class="br0">(</span>x, y<span class="br0">)</span> = target_tile<span class="br0">(</span>max_range<span class="br0">)</span>
        <span class="kw1">if</span> x <span class="kw1">is</span> <span class="kw2">None</span>:  <span class="co1">#player cancelled</span>
            <span class="kw1">return</span> <span class="kw2">None</span>
&nbsp;
        <span class="co1">#return the first clicked monster, otherwise continue looping</span>
        <span class="kw1">for</span> obj <span class="kw1">in</span> objects:
            <span class="kw1">if</span> obj.<span class="me1">x</span> == x <span class="kw1">and</span> obj.<span class="me1">y</span> == y <span class="kw1">and</span> obj.<span class="me1">fighter</span> <span class="kw1">and</span> obj <span class="sy0">!</span>= player:
                <span class="kw1">return</span> obj</pre></div></div></div>
<p><br>
The Confuse spell is a bit weak, since monsters that move randomly can be hard to hit before the spell runs out. So we'll compensate a bit by letting the player choose any target for it; conveniently testing our new function. Just replace the first 5 lines of the <i>cast_confuse</i> function with:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="co1">#ask the player for a target to confuse</span>
    message<span class="br0">(</span><span class="st0">'Left-click an enemy to confuse it, or right-click to cancel.'</span>, libtcod.<span class="me1">light_cyan</span><span class="br0">)</span>
    monster = target_monster<span class="br0">(</span>CONFUSE_RANGE<span class="br0">)</span>
    <span class="kw1">if</span> monster <span class="kw1">is</span> <span class="kw2">None</span>: <span class="kw1">return</span> <span class="st0">'cancelled'</span></pre></div></div></div>
<p><br>
</p>
<h2> <span class="mw-headline" id="Dropping_items"> Dropping items </span></h2>
<p>Right, there's an inventory feature that didn't make it into Part 8, since it was getting too long. You'll miss it when you hit the maximum number of items in your inventory: dropping items. A new method in the Item component will do that. To drop an item you just add it to the map's objects and remove it from the inventory. Then you must set its coordinates to the player's, so it appears below the player:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">def</span> drop<span class="br0">(</span><span class="kw2">self</span><span class="br0">)</span>:
        <span class="co1">#add to the map and remove from the player's inventory. also, place it at the player's coordinates</span>
        objects.<span class="me1">append</span><span class="br0">(</span><span class="kw2">self</span>.<span class="me1">owner</span><span class="br0">)</span>
        inventory.<span class="me1">remove</span><span class="br0">(</span><span class="kw2">self</span>.<span class="me1">owner</span><span class="br0">)</span>
        <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">x</span> = player.<span class="me1">x</span>
        <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">y</span> = player.<span class="me1">y</span>
        message<span class="br0">(</span><span class="st0">'You dropped a '</span> + <span class="kw2">self</span>.<span class="me1">owner</span>.<span class="me1">name</span> + <span class="st0">'.'</span>, libtcod.<span class="me1">yellow</span><span class="br0">)</span></pre></div></div></div>
<p><br>
To let the player choose an item to drop, we'll call the <i>inventory_menu</i> function when the player presses the D key, then drop the chosen item. Add this to <i>handle_keys</i>, after the inventory key:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            <span class="kw1">if</span> key_char == <span class="st0">'d'</span>:
                <span class="co1">#show the inventory; if an item is selected, drop it</span>
                chosen_item = inventory_menu<span class="br0">(</span><span class="st0">'Press the key next to an item to drop it, or any other to cancel.<span class="es0">\n</span>'</span><span class="br0">)</span>
                <span class="kw1">if</span> chosen_item <span class="kw1">is</span> <span class="kw1">not</span> <span class="kw2">None</span>:
                    chosen_item.<span class="me1">drop</span><span class="br0">(</span><span class="br0">)</span></pre></div></div></div>
<p><br>
Some new spells, targeting, dropping items -- that's enough for now! See how the spells affect your strategy, they'll surely make things much more interesting!
</p><p><br>
The whole code is available <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9_code" title="Complete Roguelike Tutorial, using python+libtcod, part 9 code">here</a>.
</p><p><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_10" title="Complete Roguelike Tutorial, using python+libtcod, part 10">Go on to the next part</a>.
</p>
<!-- 
NewPP limit report
Preprocessor node count: 213/1000000
Post-expand include size: 0/2097152 bytes
Template argument size: 0/2097152 bytes
Expensive parser function count: 0/100
-->

<!-- Saved in parser cache with key 133099-basin:pcache:idhash:3917-0!*!0!!en!*!* and timestamp 20131213190712 -->
</div><div class="printfooter">
Retrieved from "<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&oldid=35444">http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&amp;oldid=35444</a>"</div>
		<div id="catlinks" class="catlinks"><div id="mw-normal-catlinks" class="mw-normal-catlinks"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Categories" title="Special:Categories">Category</a>: <ul><li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Category:Developing" title="Category:Developing">Developing</a></li></ul></div></div>		<!-- end content -->
				<div class="visualClear"></div>
	</div>
</div></div>
<div id="column-one">
	<div id="p-cactions" class="portlet">
		<h5>Views</h5>
		<div class="pBody">
			<ul>
				<li id="ca-nstab-main" class="selected"><a href="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin.html" primary="1" context="subject" title="View the content page [alt-c]" accesskey="c">Page</a></li>
				<li id="ca-talk" class="new"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Talk:Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&action=edit&redlink=1" primary="1" context="talk" title="Discussion about the content page [alt-t]" accesskey="t">Discussion</a></li>
				<li id="ca-viewsource"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&action=edit" primary="1" title="This page is protected.
You can view its source [alt-e]" accesskey="e">View source</a></li>
				<li id="ca-history"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&action=history" rel="archives" title="Past revisions of this page [alt-h]" accesskey="h">History</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-personal">
		<h5>Personal tools</h5>
		<div class="pBody">
			<ul>
				<li id="pt-login"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:UserLogin&returnto=Complete+Roguelike+Tutorial%2C+using+python%2Blibtcod%2C+part+9" title="You are encouraged to log in; however, it is not mandatory [alt-o]" accesskey="o">Log in / create account</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-logo">
<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" style="background-image: url(/skins/roguebasin/RogueBasin_logo.png);" title="Visit the main page"></a>
	</div>
	<div class="generated-sidebar portlet" id="p-navigation">
		<h5>Navigation</h5>
		<div class="pBody">
			<ul>
				<li id="n-mainpage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" title="Visit the main page [alt-z]" accesskey="z">Main Page</a></li>
				<li id="n-portal"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Community_portal" title="About the project, what you can do, where to find things">Community portal</a></li>
				<li id="n-recentchanges"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges" title="A list of recent changes in the wiki [alt-r]" accesskey="r">Recent changes</a></li>
				<li id="n-randompage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Random" title="Load a random page [alt-x]" accesskey="x">Random page</a></li>
				<li id="n-help"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Help" title="The place to find out">Help</a></li>
			</ul>
		</div>
	</div>
	<div id="p-search" class="portlet">
		<h5><label for="searchInput">Search</label></h5>
		<div id="searchBody" class="pBody">
			<form action="http://roguebasin.roguelikedevelopment.org/index.php" id="searchform">
				<input type="hidden" name="title" value="Special:Search">
				<input type="search" name="search" title="Search RogueBasin [alt-f]" accesskey="f" id="searchInput">
				<input type="submit" name="go" value="Go" title="Go to a page with this exact name if exists" id="searchGoButton" class="searchButton">&nbsp;
				<input type="submit" name="fulltext" value="Search" title="Search the pages for this text" id="mw-searchButton" class="searchButton">
			</form>
		</div>
	</div>
	<div class="portlet" id="p-tb">
		<h5>Toolbox</h5>
		<div class="pBody">
			<ul>
				<li id="t-whatlinkshere"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:WhatLinksHere/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9" title="A list of all wiki pages that link here [alt-j]" accesskey="j">What links here</a></li>
				<li id="t-recentchangeslinked"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChangesLinked/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9" title="Recent changes in pages linked from this page [alt-k]" accesskey="k">Related changes</a></li>
				<li id="t-specialpages"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:SpecialPages" title="A list of all special pages [alt-q]" accesskey="q">Special pages</a></li>
				<li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&printable=yes" rel="alternate">Printable version</a></li>
				<li id="t-permalink"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_9&oldid=35444" title="Permanent link to this revision of the page">Permanent link</a></li>
			</ul>
		</div>
	</div>
</div><!-- end of the left (by default at least) column -->
<div class="visualClear"></div>
<div id="footer">
	<div id="f-poweredbyico">
		<a href="http://www.mediawiki.org/"><img src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" width="88" height="31"></a>
	</div>
	<ul id="f-list">
		<li id="lastmod"> This page was last modified on 24 May 2013, at 13:44.</li>
		<li id="viewcount">This page has been accessed 9,097 times.</li>
		<li id="privacy"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Privacy_policy" title="RogueBasin:Privacy policy">Privacy policy</a></li>
		<li id="about"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:About" title="RogueBasin:About">About RogueBasin</a></li>
		<li id="disclaimer"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:General_disclaimer" title="RogueBasin:General disclaimer">Disclaimers</a></li>
	</ul>
</div>
</div>
<script>if(window.mw){
mw.loader.load(["mediawiki.user","mediawiki.page.ready"], null, true);
}</script><script src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/load(3).php" type="text/javascript"></script>
<script src="./Complete Roguelike Tutorial, using python+libtcod, part 9 - RogueBasin_files/load(4).php"></script>
<!-- Served in 0.174 secs. --><autoscroll_cursor hidden=""></autoscroll_cursor></body></html>